import React, { useState, useEffect, useRef, useCallback } from 'react';
import { FormInstance, FormItemProps, FormProps } from 'antd/es/form';
import { Form, Row, Col } from 'antd';
import RcResizeObserver from 'rc-resize-observer';
import useMediaQuery from 'use-media-antd-query';
import useMergeValue from 'use-merge-value';
import { ConfigConsumer, ConfigConsumerProps } from 'antd/lib/config-provider';
import classNames from 'classnames';

import { useDeepCompareEffect, genColumnKey } from '../component/util';
import { useIntl } from '../component/intlContext';
import Container from '../container';
import { ProTableTypes } from '../Table';
import { ProColumns } from '../index';
import FormOption, { FormOptionProps } from './FormOption';
import proFormItemRender from './FormItemRender';
import { FormInputRender as FormInputComponent } from './FormInputRender';
import getDefaultSearch, { defaultColConfig } from './getDefaultSearch';
import conversionValue from './conversionValue';
import { getRowNumber, getLastRowSpanNumber } from './getRowNumber';
import './index.less';

/**
 * 用于配置操作栏
 */
export interface SearchConfig {
  /**
   * 查询按钮的文本
   */
  searchText?: string;
  /**
   * 重置按钮的文本
   */
  resetText?: string;
  span?: number | typeof defaultColConfig;
  /**
   * 收起按钮的 render
   */
  collapseRender?: (
    collapsed: boolean,
    /**
     * 是否应该展示，有两种情况
     * 列只有三列，不需要收起
     * form 模式 不需要收起
     */
    showCollapseButton?: boolean,
  ) => React.ReactNode;
  /**
   * 底部操作栏的 render
   * searchConfig 基础的配置
   * props 更加详细的配置
   * {
      type?: 'form' | 'list' | 'table' | 'cardList' | undefined;
      form: FormInstance;
      submit: () => void;
      collapse: boolean;
      setCollapse: (collapse: boolean) => void;
      showCollapseButton: boolean;
   * }
   */
  optionRender?:
    | ((
        searchConfig: Omit<SearchConfig, 'optionRender'>,
        props: Omit<FormOptionProps, 'searchConfig'>,
      ) => React.ReactNode)
    | false;
  /**
   * 是否收起
   */
  collapsed?: boolean;
  /**
   * 收起按钮的事件
   */
  onCollapse?: (collapsed: boolean) => void;
  /**
   * 提交按钮的文本
   */
  submitText?: string;
}

/**
 * 获取最后一行的 offset，保证在最后一列
 * @param length
 * @param span
 */
const getOffset = (span: number = 8, formColsArray: number[]) => {
  const lastRowSpan = getLastRowSpanNumber(formColsArray);
  const rest = 24 - lastRowSpan;

  if (rest < span) {
    return 24 - span;
  } else {
    return rest - span;
  }
};

export interface TableFormItem<T> extends Omit<FormItemProps, 'children'> {
  onSubmit?: (value: T) => void;
  onReset?: () => void;
  form?: Omit<FormProps, 'form'>;
  type?: ProTableTypes;
  dateFormatter?: 'string' | 'number' | false;
  search?: boolean | SearchConfig;
  formRef?: React.MutableRefObject<FormInstance | undefined> | ((actionRef: FormInstance) => void);
  formColConfig?: Partial<typeof defaultColConfig>;
  searchOptionColConfig?: Partial<typeof defaultColConfig>;
}

export const FormInputRender = FormInputComponent;

/**
 * 合并用户和默认的配置
 * @param span
 * @param size
 */
const getSpanConfig = (
  span: number | typeof defaultColConfig,
  size: keyof typeof defaultColConfig,
): number => {
  if (typeof span === 'number') {
    return span;
  }
  const config = {
    ...defaultColConfig,
    ...span,
  };
  return config[size];
};

const FormSearch = <T, U = {}>({
  onSubmit,
  formRef,
  dateFormatter = 'string',
  search: propsSearch,
  type,
  form: formConfig = {},
  onReset,
  formColConfig,
  searchOptionColConfig,
}: TableFormItem<T>) => {
  /**
   * 为了支持 dom 的消失，支持了这个 api
   */
  const intl = useIntl();

  const [form] = Form.useForm();
  const formInstanceRef = useRef<
    Omit<FormInstance, 'scrollToField' | '__INTERNAL__'> | undefined | any
  >();
  const searchConfig = getDefaultSearch(propsSearch, intl, type === 'form', formColConfig);
  const { span } = searchConfig; //默认span

  const counter = Container.useContainer();
  const [collapse, setCollapse] = useMergeValue<boolean>(true, {
    value: searchConfig.collapsed,
    onChange: searchConfig.onCollapse,
  });
  const [proColumnsMap, setProColumnsMap] = useState<{
    [key: string]: ProColumns<any>;
  }>({});

  const windowSize = useMediaQuery();
  const [colSize, setColSize] = useState(getSpanConfig(span || 8, windowSize));
  const [formCols, setFormCols] = useState<string>('');
  const [formHeight, setFormHeight] = useState<number | undefined>(60);

  const isForm = type === 'form';

  /**
   *提交表单，根据两种模式不同，方法不相同
   */
  const submit = async () => {
    // 如果不是表单模式，不用进行验证
    if (!isForm) {
      const value = form.getFieldsValue();
      if (onSubmit) {
        onSubmit(conversionValue(value, dateFormatter, proColumnsMap) as T);
      }
      return;
    }
    try {
      const value = await form.validateFields();
      if (onSubmit) {
        onSubmit(conversionValue(value, dateFormatter, proColumnsMap) as T);
      }
    } catch (error) {
      // console.log(error)
    }
  };

  useEffect(() => {
    if (!formRef) {
      return;
    }
    if (typeof formRef === 'function') {
      formRef(form);
    }
    if (formRef && typeof formRef !== 'function') {
      // eslint-disable-next-line no-param-reassign
      formRef.current = {
        ...form,
        submit: () => {
          submit();
          form.submit();
        },
      };
    }
  }, []);

  useEffect(() => {
    //不是数字类型根据屏幕变化更新宽度
    if (typeof span !== 'number') {
      setColSize(getSpanConfig(span || 8, windowSize));
    }
  }, [windowSize]);

  useDeepCompareEffect(() => {
    const tempMap = {};
    counter.proColumns.forEach((item) => {
      tempMap[genColumnKey(item.key, item.dataIndex, item.index) || 'null'] = item;
    });
    setProColumnsMap(tempMap);
  }, [counter.proColumns]);

  const columnsList = counter.proColumns
    .filter((item) => {
      const { valueType } = item;
      if (item.hideInSearch && type !== 'form') {
        return false;
      }
      if (type === 'form' && item.hideInForm) {
        return false;
      }
      if (
        valueType !== 'index' &&
        valueType !== 'indexBorder' &&
        valueType !== 'option' &&
        (item.key || item.dataIndex)
      ) {
        return true;
      }
      return false;
    })
    .sort((a, b) => {
      if (a && b) {
        return (b.order || 0) - (a.order || 0);
      }
      if (a && a.order) {
        return -1;
      }
      if (b && b.order) {
        return 1;
      }
      return 0;
    });

  useEffect(() => {
    if (type !== 'form') {
      const formCols = columnsList.map((item) => {
        const formItemColConfig = item?.formItemColConfig;
        const hasSpan = formItemColConfig && formItemColConfig.hasOwnProperty('span');

        const currentSizeSpan =
          formItemColConfig &&
          getSpanConfig(hasSpan ? formItemColConfig['span'] : formItemColConfig || 8, windowSize);

        const formItemColSize = (formItemColConfig && currentSizeSpan) || colSize;
        return formItemColSize;
      });

      setFormCols(formCols.join(','));
    }
  }, [columnsList, windowSize]);

  const colConfig = typeof span === 'number' ? { span } : span;

  // 这么做是为了在用户修改了输入的时候触发一下子节点的render
  const [, updateState] = React.useState();
  const forceUpdate = useCallback(() => updateState({}), []);
  const formColsArray = formCols
    ? formCols.split(',').map((item: string): number => parseInt(item))
    : [];
  const rowNumber = getRowNumber(formColsArray, colSize);

  //计算要不要展开
  const domList = formInstanceRef.current
    ? columnsList
        .map((item) => {
          return proFormItemRender({
            isForm,
            formInstance: formInstanceRef.current,
            collapse,
            item,
            type,
            colConfig,
            intl,
          });
        })
        .filter((_, index) => (collapse && type !== 'form' ? index < rowNumber : true))
        .filter((item) => !!item)
    : [];
  // formInstanceRef.current? columnsList.map((item)=>{return item.rowName}):['default']

  return (
    <ConfigConsumer>
      {({ getPrefixCls }: ConfigConsumerProps) => {
        const className = getPrefixCls('pro-table-search');
        const formClassName = getPrefixCls('pro-table-form');
        return (
          <div
            className={classNames(className, {
              [formClassName]: isForm,
            })}
            style={
              isForm
                ? undefined
                : {
                    height: formHeight,
                  }
            }
          >
            <RcResizeObserver
              onResize={({ height }) => {
                if (type === 'form') {
                  return;
                }
                setFormHeight(height + 20);
              }}
            >
              <div>
                <Form
                  {...formConfig}
                  form={form}
                  onValuesChange={() => forceUpdate()}
                  initialValues={columnsList.reduce(
                    (pre, item) => {
                      const key = genColumnKey(item.key, item.dataIndex, item.index) || '';
                      if (item.initialValue) {
                        return {
                          ...pre,
                          [key]: item.initialValue,
                        };
                      }
                      return pre;
                    },
                    { ...formConfig.initialValues },
                  )}
                >
                  <Form.Item shouldUpdate noStyle>
                    {(formInstance) => {
                      setTimeout(() => {
                        formInstanceRef.current = formInstance;
                      }, 0);
                      return null;
                    }}
                  </Form.Item>
                  <Row gutter={16} justify="start">
                    <Form.Item label={isForm && ' '} shouldUpdate noStyle>
                      <>{domList}</>
                    </Form.Item>
                    {domList[0] && type !== 'form' && (
                      <Col
                        span={24}
                        {...colConfig}
                        {...searchOptionColConfig}
                        offset={getOffset(
                          colSize,
                          formColsArray.filter((_, index) => index < domList.length),
                        )}
                        key="option"
                        className={classNames(`${className}-option`, {
                          [`${className}-form-option`]: isForm,
                        })}
                      >
                        <Form.Item label={isForm && ' '}>
                          <FormOption
                            showCollapseButton={rowNumber < formColsArray.length && !isForm}
                            searchConfig={searchConfig}
                            submit={submit}
                            onReset={onReset}
                            form={{
                              ...form,
                              submit: () => {
                                submit();
                                form.submit();
                              },
                            }}
                            type={type}
                            collapse={collapse}
                            setCollapse={setCollapse}
                          />
                        </Form.Item>
                      </Col>
                    )}
                  </Row>
                </Form>
              </div>
            </RcResizeObserver>
          </div>
        );
      }}
    </ConfigConsumer>
  );
};

export default FormSearch;
